/*
 * FreeRTOS Kernel V10.4.6
 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.    All Rights Reserved.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * https://www.FreeRTOS.org
 * https://github.com/FreeRTOS
 *
 */


#ifndef PORTMACRO_H
#define PORTMACRO_H

/* *INDENT-OFF* */
#ifdef __cplusplus
        extern "C" {
#endif
/* *INDENT-ON* */

/*-----------------------------------------------------------
 * Port specific definitions.
 *
 * The settings in this file configure FreeRTOS correctly for the
 * given hardware and compiler.
 *
 * These settings should not be altered.
 *-----------------------------------------------------------
 */

/* Type definitions. */
#define portCHAR                    char
#define portFLOAT                 float
#define portDOUBLE                double
#define portLONG                    long
#define portSHORT                 short
#define portSTACK_TYPE        uint32_t
#define portBASE_TYPE         long

typedef portSTACK_TYPE     StackType_t;
typedef long                         BaseType_t;
typedef unsigned long        UBaseType_t;

#if ( configUSE_16_BIT_TICKS == 1 )
        typedef uint16_t         TickType_t;
        #define portMAX_DELAY                            ( TickType_t ) 0xffff
#else
        typedef uint32_t         TickType_t;
        #define portMAX_DELAY                            ( TickType_t ) 0xffffffffUL

/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
 * not need to be guarded with a critical section. */
        #define portTICK_TYPE_IS_ATOMIC        1
#endif
/*-----------------------------------------------------------*/

/* MPU specific constants. */
#define portUSING_MPU_WRAPPERS                                                                     1
#define portPRIVILEGE_BIT                                                                                ( 0x80000000UL )

#define portMPU_REGION_READ_WRITE                                                                ( 0x03UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY                                            ( 0x05UL << 24UL )
#define portMPU_REGION_READ_ONLY                                                                 ( 0x06UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE                                         ( 0x01UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY        ( 0x02UL << 24UL )
#define portMPU_REGION_CACHEABLE_BUFFERABLE                                            ( 0x07UL << 16UL )
#define portMPU_REGION_EXECUTE_NEVER                                                         ( 0x01UL << 28UL )

/* Location of the TEX,S,C,B bits in the MPU Region Attribute and Size
 * Register (RASR). */
#define portMPU_RASR_TEX_S_C_B_LOCATION                                                    ( 16UL )
#define portMPU_RASR_TEX_S_C_B_MASK                                                            ( 0x3FUL )

/* MPU settings that can be overriden in FreeRTOSConfig.h. */
#ifndef configTOTAL_MPU_REGIONS
        /* Define to 8 for backward compatibility. */
        #define configTOTAL_MPU_REGIONS        ( 8UL )
#endif

/*
 * The TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits define the
 * memory type, and where necessary the cacheable and shareable properties
 * of the memory region.
 *
 * The TEX, C, and B bits together indicate the memory type of the region,
 * and:
 * - For Normal memory, the cacheable properties of the region.
 * - For Device memory, whether the region is shareable.
 *
 * For Normal memory regions, the S bit indicates whether the region is
 * shareable. For Strongly-ordered and Device memory, the S bit is ignored.
 *
 * See the following two tables for setting TEX, S, C and B bits for
 * unprivileged flash, privileged flash and privileged RAM regions.
 *
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | TEX | C | B | Memory type                        |    Description or Normal region cacheability                         |    Shareable?                         |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 000 | 0 | 0 | Strongly-ordered             |    Strongly ordered                                                                            |    Shareable                            |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 000 | 0 | 1 | Device                                 |    Shared device                                                                                 |    Shareable                            |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 000 | 1 | 0 | Normal                                 |    Outer and inner     write-through; no write allocate        |    S bit                                    |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 000 | 1 | 1 | Normal                                 |    Outer and inner     write-back; no write allocate             |    S bit                                    |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 001 | 0 | 0 | Normal                                 |    Outer and inner     Non-cacheable                                             |    S bit                                    |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 001 | 0 | 1 | Reserved                             |    Reserved                                                                                            |    Reserved                             |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 001 | 1 | 0 | IMPLEMENTATION DEFINED |    IMPLEMENTATION DEFINED                                                                |    IMPLEMENTATION DEFINED |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 001 | 1 | 1 | Normal                                 |    Outer and inner     write-back; write and read allocate |    S bit                                    |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 010 | 0 | 0 | Device                                 |    Non-shared device                                                                         |    Not shareable                    |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 010 | 0 | 1 | Reserved                             |    Reserved                                                                                            |    Reserved                             |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 010 | 1 | X | Reserved                             |    Reserved                                                                                            |    Reserved                             |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 011 | X | X | Reserved                             |    Reserved                                                                                            |    Reserved                             |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 | 1BB | A | A | Normal                                 | Cached memory, with AA and BB indicating the inner and |    Reserved                             |
 |         |     |     |                                                | outer cacheability rules that must be exported on the    |                                                 |
 |         |     |     |                                                | bus. See the table below for the cacheability policy     |                                                 |
 |         |     |     |                                                | encoding. memory, BB=Outer policy, AA=Inner policy.        |                                                 |
 +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
 |
 +-----------------------------------------+----------------------------------------+
 | AA or BB subfield of {TEX,C,B} encoding |    Cacheability policy                                     |
 +-----------------------------------------+----------------------------------------+
 | 00                                                                            |    Non-cacheable                                                 |
 +-----------------------------------------+----------------------------------------+
 | 01                                                                            |    Write-back, write and     read allocate |
 +-----------------------------------------+----------------------------------------+
 | 10                                                                            |    Write-through, no write     allocate        |
 +-----------------------------------------+----------------------------------------+
 | 11                                                                            |    Write-back, no write     allocate             |
 +-----------------------------------------+----------------------------------------+
 */

/* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for Flash
 * region. */
#ifndef configTEX_S_C_B_FLASH
        /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */
        #define configTEX_S_C_B_FLASH        ( 0x07UL )
#endif

/* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for SRAM
 * region. */
#ifndef configTEX_S_C_B_SRAM
        /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */
        #define configTEX_S_C_B_SRAM                    ( 0x07UL )
#endif

#define portUNPRIVILEGED_FLASH_REGION         ( 0UL )
#define portPRIVILEGED_FLASH_REGION             ( 1UL )
#define portPRIVILEGED_RAM_REGION                 ( 2UL )
#define portGENERAL_PERIPHERALS_REGION        ( 3UL )
#define portSTACK_REGION                                    ( 4UL )
#define portFIRST_CONFIGURABLE_REGION         ( 5UL )
#define portTOTAL_NUM_REGIONS                         ( configTOTAL_MPU_REGIONS )
#define portNUM_CONFIGURABLE_REGIONS            ( portTOTAL_NUM_REGIONS - portFIRST_CONFIGURABLE_REGION )
#define portLAST_CONFIGURABLE_REGION            ( portTOTAL_NUM_REGIONS - 1 )

void vPortSwitchToUserMode( void );
#define portSWITCH_TO_USER_MODE()        vPortSwitchToUserMode()

typedef struct MPU_REGION_REGISTERS
{
        uint32_t ulRegionBaseAddress;
        uint32_t ulRegionAttribute;
} xMPU_REGION_REGISTERS;

/* Plus 1 to create space for the stack region. */
typedef struct MPU_SETTINGS
{
        xMPU_REGION_REGISTERS xRegion[ portTOTAL_NUM_REGIONS ];
} xMPU_SETTINGS;

/* Architecture specifics. */
#define portSTACK_GROWTH                    ( -1 )
#define portTICK_PERIOD_MS                ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT                8

/* Constants used with memory barrier intrinsics. */
#define portSY_FULL_READ_WRITE        ( 15 )

/*-----------------------------------------------------------*/

/* SVC numbers for various services. */
#define portSVC_START_SCHEDULER        0
#define portSVC_YIELD                            1
#define portSVC_RAISE_PRIVILEGE        2

/* Scheduler utilities. */

#define portYIELD()        __asm{ SVC portSVC_YIELD }
#define portYIELD_WITHIN_API()                                                    \
        {                                                                                                     \
                /* Set a PendSV to request a context switch. */ \
                portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
                                                                                                                \
                /* Barriers are normally not required but do ensure the code is completely \
                 * within the specified behaviour for the architecture. */ \
                __dsb( portSY_FULL_READ_WRITE );                                                     \
                __isb( portSY_FULL_READ_WRITE );                                                     \
        }
/*-----------------------------------------------------------*/

#define portNVIC_INT_CTRL_REG         ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT        ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired )        do { if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } while( 0 )
#define portYIELD_FROM_ISR( x )                                         portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/

/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );

#define portDISABLE_INTERRUPTS()                                    vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS()                                     vPortSetBASEPRI( 0 )
#define portENTER_CRITICAL()                                            vPortEnterCritical()
#define portEXIT_CRITICAL()                                             vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR()                 ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x )        vPortSetBASEPRI( x )

/*-----------------------------------------------------------*/

/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
        #define configUSE_PORT_OPTIMISED_TASK_SELECTION        1
#endif

#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1

/* Check the configuration. */
        #if ( configMAX_PRIORITIES > 32 )
                #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32.    It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
        #endif

/* Store/clear the ready priorities in a bit map. */
        #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities )        ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
        #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities )         ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )

/*-----------------------------------------------------------*/

        #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )        uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/

/* Task function macros as described on the FreeRTOS.org WEB site.    These are
 * not necessary for to use this port.    They are defined so the common demo files
 * (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters )        void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters )                    void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/

#ifdef configASSERT
        void vPortValidateInterruptPriority( void );
        #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID()        vPortValidateInterruptPriority()
#endif

/* portNOP() is not required by this port. */
#define portNOP()

#define portINLINE                            __inline

#ifndef portFORCE_INLINE
        #define portFORCE_INLINE        __forceinline
#endif
/*-----------------------------------------------------------*/

extern BaseType_t xIsPrivileged( void );
extern void vResetPrivilege( void );

/**
 * @brief Checks whether or not the processor is privileged.
 *
 * @return 1 if the processor is already privileged, 0 otherwise.
 */
#define portIS_PRIVILEGED()            xIsPrivileged()

/**
 * @brief Raise an SVC request to raise privilege.
 */
#define portRAISE_PRIVILEGE()        __asm { svc portSVC_RAISE_PRIVILEGE }

/**
 * @brief Lowers the privilege level by setting the bit 0 of the CONTROL
 * register.
 */
#define portRESET_PRIVILEGE()        vResetPrivilege()
/*-----------------------------------------------------------*/

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
        __asm
        {
                /* Barrier instructions are not used as this function is only used to
                 * lower the BASEPRI value. */
/* *INDENT-OFF* */
                msr basepri, ulBASEPRI
/* *INDENT-ON* */
        }
}
/*-----------------------------------------------------------*/

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
        uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

        __asm
        {
                /* Set BASEPRI to the max syscall priority to effect a critical
                 * section. */
/* *INDENT-OFF* */
                msr basepri, ulNewBASEPRI
                dsb
                isb
/* *INDENT-ON* */
        }
}
/*-----------------------------------------------------------*/

static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
        __asm
        {
                /* Set BASEPRI to 0 so no interrupts are masked.    This function is only
                 * used to lower the mask in an interrupt, so memory barriers are not
                 * used. */
/* *INDENT-OFF* */
                msr basepri, # 0
/* *INDENT-ON* */
        }
}
/*-----------------------------------------------------------*/

static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
        uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

        __asm
        {
                /* Set BASEPRI to the max syscall priority to effect a critical
                 * section. */
/* *INDENT-OFF* */
                mrs ulReturn, basepri
                msr basepri, ulNewBASEPRI
                dsb
                isb
/* *INDENT-ON* */
        }

        return ulReturn;
}
/*-----------------------------------------------------------*/

static portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void )
{
        uint32_t ulCurrentInterrupt;
        BaseType_t xReturn;

        /* Obtain the number of the currently executing interrupt. */
        __asm
        {
                mrs ulCurrentInterrupt, ipsr
        }

        if( ulCurrentInterrupt == 0 )
        {
                xReturn = pdFALSE;
        }
        else
        {
                xReturn = pdTRUE;
        }

        return xReturn;
}
/*-----------------------------------------------------------*/

#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
        #warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security. https://www.FreeRTOS.org/FreeRTOS-V10.3.x.html"
        #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY        0
#endif
/*-----------------------------------------------------------*/

/* *INDENT-OFF* */
#ifdef __cplusplus
        }
#endif
/* *INDENT-ON* */

#endif /* PORTMACRO_H */
